{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as K\n",
    "import matplotlib.pyplot as plt\n",
    "from tensorflow.keras import regularizers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(11)\n",
    "tf.random.set_seed(11)\n",
    "batch_size = 256\n",
    "max_epochs = 50\n",
    "learning_rate = 1e-3\n",
    "momentum = 8e-1\n",
    "hidden_dim = 128\n",
    "original_dim = 784"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x_train, _), (x_test, _) = K.datasets.mnist.load_data()\n",
    "\n",
    "x_train = x_train / 255.\n",
    "x_test = x_test / 255.\n",
    "\n",
    "x_train = x_train.astype(np.float32)\n",
    "x_test = x_test.astype(np.float32)\n",
    "\n",
    "x_train = np.reshape(x_train, (x_train.shape[0], 784))\n",
    "x_test = np.reshape(x_test, (x_test.shape[0], 784))\n",
    "\n",
    "training_dataset = tf.data.Dataset.from_tensor_slices(x_train).batch(batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class SparseEncoder(K.layers.Layer):\n",
    "    def __init__(self, hidden_dim):\n",
    "        super(SparseEncoder, self).__init__()\n",
    "        self.hidden_layer = K.layers.Dense(units=hidden_dim, \n",
    "                    activation=tf.nn.relu, activity_regularizer=regularizers.l1(10e-5))\n",
    "        \n",
    "    \n",
    "    def call(self, input_features):\n",
    "        activation = self.hidden_layer(input_features)\n",
    "        return activation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class SparseDecoder(K.layers.Layer):\n",
    "    def __init__(self, hidden_dim, original_dim):\n",
    "        super(SparseDecoder, self).__init__()\n",
    "        self.output_layer = K.layers.Dense(units=original_dim, activation=tf.nn.relu)\n",
    "  \n",
    "    def call(self, encoded):\n",
    "        activation = self.output_layer(encoded)\n",
    "        return activation "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SparseAutoencoder(K.Model):\n",
    "    def __init__(self, hidden_dim, original_dim):\n",
    "        super(SparseAutoencoder, self).__init__()\n",
    "        self.loss = []\n",
    "        self.encoder = SparseEncoder(hidden_dim=hidden_dim)\n",
    "        self.decoder = SparseDecoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "\n",
    "    def call(self, input_features):\n",
    "        encoded = self.encoder(input_features)\n",
    "        reconstructed = self.decoder(encoded)\n",
    "        return reconstructed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "autoencoder = SparseAutoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "opt = tf.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)\n",
    "\n",
    "def loss(preds, real):\n",
    "    return tf.reduce_mean(tf.square(tf.subtract(preds, real))) \n",
    "\n",
    "def train(loss, model, opt, original):\n",
    "    with tf.GradientTape() as tape:\n",
    "        preds = model(original)\n",
    "        reconstruction_error = loss(preds, original)\n",
    "    gradients = tape.gradient(reconstruction_error, model.trainable_variables)\n",
    "    gradient_variables = zip(gradients, model.trainable_variables)\n",
    "    opt.apply_gradients(gradient_variables)\n",
    "  \n",
    "    return reconstruction_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_loop(model, opt, loss, dataset, epochs=20):\n",
    "    for epoch in range(epochs):\n",
    "        epoch_loss = 0\n",
    "        for step, batch_features in enumerate(dataset):\n",
    "            loss_values = train(loss, model, opt, batch_features)\n",
    "            epoch_loss += loss_values\n",
    "        model.loss.append(epoch_loss)\n",
    "        print('Epoch {}/{}. Loss: {}'.format(epoch + 1, epochs, epoch_loss.numpy()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50. Loss: 5.1587958335876465\n",
      "Epoch 2/50. Loss: 3.072758913040161\n",
      "Epoch 3/50. Loss: 2.9567911624908447\n",
      "Epoch 4/50. Loss: 2.8891077041625977\n",
      "Epoch 5/50. Loss: 2.893104314804077\n",
      "Epoch 6/50. Loss: 2.843897581100464\n",
      "Epoch 7/50. Loss: 2.843674898147583\n",
      "Epoch 8/50. Loss: 2.8288328647613525\n",
      "Epoch 9/50. Loss: 2.807680368423462\n",
      "Epoch 10/50. Loss: 2.851358413696289\n",
      "Epoch 11/50. Loss: 2.804849863052368\n",
      "Epoch 12/50. Loss: 2.7799880504608154\n",
      "Epoch 13/50. Loss: 2.8308520317077637\n",
      "Epoch 14/50. Loss: 2.81044340133667\n",
      "Epoch 15/50. Loss: 2.814807176589966\n",
      "Epoch 16/50. Loss: 2.8045241832733154\n",
      "Epoch 17/50. Loss: 2.7953529357910156\n",
      "Epoch 18/50. Loss: 2.801511526107788\n",
      "Epoch 19/50. Loss: 2.800142288208008\n",
      "Epoch 20/50. Loss: 2.812126398086548\n",
      "Epoch 21/50. Loss: 2.806365966796875\n",
      "Epoch 22/50. Loss: 2.826596736907959\n",
      "Epoch 23/50. Loss: 2.8027992248535156\n",
      "Epoch 24/50. Loss: 2.792048931121826\n",
      "Epoch 25/50. Loss: 2.807739019393921\n",
      "Epoch 26/50. Loss: 2.8026280403137207\n",
      "Epoch 27/50. Loss: 2.8349876403808594\n",
      "Epoch 28/50. Loss: 2.777519702911377\n",
      "Epoch 29/50. Loss: 2.781268358230591\n",
      "Epoch 30/50. Loss: 2.8068041801452637\n",
      "Epoch 31/50. Loss: 2.818871259689331\n",
      "Epoch 32/50. Loss: 2.8017191886901855\n",
      "Epoch 33/50. Loss: 2.8185043334960938\n",
      "Epoch 34/50. Loss: 2.8035051822662354\n",
      "Epoch 35/50. Loss: 2.820244312286377\n",
      "Epoch 36/50. Loss: 2.800128698348999\n",
      "Epoch 37/50. Loss: 2.798171281814575\n",
      "Epoch 38/50. Loss: 2.8326492309570312\n",
      "Epoch 39/50. Loss: 2.7774178981781006\n",
      "Epoch 40/50. Loss: 2.786750078201294\n",
      "Epoch 41/50. Loss: 2.819849729537964\n",
      "Epoch 42/50. Loss: 2.800732374191284\n",
      "Epoch 43/50. Loss: 2.808854579925537\n",
      "Epoch 44/50. Loss: 2.799129009246826\n",
      "Epoch 45/50. Loss: 2.8094983100891113\n",
      "Epoch 46/50. Loss: 2.818035364151001\n",
      "Epoch 47/50. Loss: 2.793402671813965\n",
      "Epoch 48/50. Loss: 2.829216957092285\n",
      "Epoch 49/50. Loss: 2.7824392318725586\n",
      "Epoch 50/50. Loss: 2.7979650497436523\n"
     ]
    }
   ],
   "source": [
    "model = SparseAutoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "opt = tf.keras.optimizers.Adam(learning_rate=1e-2)\n",
    "\n",
    "train_loop(model, opt, loss, training_dataset, epochs=max_epochs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "plt.plot(range(max_epochs), model.loss)\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABGoAAADjCAYAAADdR/IFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3XeYVOX1wPGzCihFEZAiSkcEqVJFQQFRrAhGFMHYjYUYY+zRX4ItPo9EYg1KEgtoCIqoSIsNUEBEqlINICBSpImiSN3fHz4ez3nZGWZnZ2bvznw/f53r++7sG2bvnTs37zknLz8/XwAAAAAAAFD8DiruBQAAAAAAAOAnPKgBAAAAAACICB7UAAAAAAAARAQPagAAAAAAACKCBzUAAAAAAAARwYMaAAAAAACAiCgVbzAvL4/e3cVnU35+ftVUvBDvY/HJz8/PS8Xr8B4WK87FLMC5mBU4F7MA52JW4FzMApyLWYFzMQvEOhfZURNdq4p7AQBEhHMRiArORSAaOBeBaOBczGI8qAEAAAAAAIgIHtQAAAAAAABEBA9qAAAAAAAAIoIHNQAAAAAAABHBgxoAAAAAAICI4EENAAAAAABARPCgBgAAAAAAICJKFfcCkDtuu+02jcuWLevGWrRoofGFF14Y8zWGDBmi8UcffeTGhg8fXtQlAgAAAABQrNhRAwAAAAAAEBE8qAEAAAAAAIgIHtQAAAAAAABEBDVqkFYjR47UOF7tGWvfvn0xx6677jqNu3fv7samTJmi8erVqxNdIopRo0aN3PGSJUs0vvnmmzV+8sknM7amXFe+fHmNBw0apLE990REZs+erXGfPn3c2KpVq9K0OgAAgMyrVKmSxrVr107oZ8L7oVtuuUXjBQsWaPz555+7efPnz09micgy7KgBAAAAAACICB7UAAAAAAAARASpT0gpm+okkni6k015+e9//6tx/fr13bzzzjtP4wYNGrix/v37a/zwww8n9HtRvE444QR3bNPe1qxZk+nlQESOOuooja+99lqNw5TENm3aaHzuuee6saeffjpNq8PPWrdurfHo0aPdWN26ddP2e8844wx3vHjxYo2//PLLtP1eJMZ+RoqIjBkzRuPf/va3Gj/zzDNu3t69e9O7sCxTrVo1jV955RWNp0+f7uYNHTpU45UrV6Z9XT+rWLGiOz7llFM0njhxosa7d+/O2JqAkuCcc87RuGfPnm6sS5cuGjds2DCh1wtTmurUqaPxIYccEvPnDj744IReH9mNHTUAAAAAAAARwYMaAAAAAACAiCD1CUXWtm1bjXv37h1z3sKFCzUOtxNu2rRJ4+3bt2tcpkwZN2/GjBkat2zZ0o1VqVIlwRUjKlq1auWOv//+e41ff/31TC8nJ1WtWtUdv/jii8W0EhRGjx49NI63fTrVwtSaq666SuO+fftmbB34hf3s+/vf/x5z3lNPPaXxc88958Z27NiR+oVlEdvtRcTfz9g0ow0bNrh5xZXuZLvyifjrvE1bXbZsWfoXVgIdfvjh7tim0zdr1kzjsPsoqWTRZcslDBgwQGOb4i0iUrZsWY3z8vKK/HvD7qZAYbCjBgAAAAAAICJ4UAMAAAAAABARPKgBAAAAAACIiIzWqAlbNdu8wLVr17qxH3/8UeOXX35Z4/Xr17t55NcWP9vON8zntHnctqbCunXrEnrtW2+91R0ff/zxMeeOGzcuoddE8bL53bZdrIjI8OHDM72cnPS73/1O4169ermx9u3bF/r1bOtXEZGDDvrl/wOYP3++xh988EGhXxu/KFXql4/ss88+u1jWENa++MMf/qBx+fLl3ZitOYX0seffMcccE3PeiBEjNLb3WCjYkUceqfHIkSPdWOXKlTW2dYFuuumm9C8shnvvvVfjevXqubHrrrtOY+6bC9a/f3+NH3roITdWq1atAn8mrGWzefPm1C8MKWGvjTfffHNaf9eSJUs0tt+DkFq2Rbq9Xov4mqm2rbqIyL59+zR+5plnNJ42bZqbF4VrJTtqAAAAAAAAIoIHNQAAAAAAABGR0dSnRx55xB3XrVs3oZ+zWza/++47N5bJLWVr1qzROPzfMmvWrIytI2reeustje02NBH/fm3ZsqXQrx22ey1dunShXwPR0rhxY43DVIlweznS429/+5vGdgtosi644IKYx6tWrdL44osvdvPCNBrE17VrV407duyocfh5lE5hm2KbjlquXDk3RupTeoTt2O+5556Efs6mlubn56d0TdmodevWGodb5637778/A6vZX9OmTd2xTRV//fXX3RifrQWz6TCPPfaYxrblvUjs8+XJJ590xzadO5l7XhxYmOJi05hs6srEiRPdvJ07d2q8bds2jcPPKXtf+vbbb7uxBQsWaPzxxx9rPHfuXDdvx44dMV8fhWPLJYj4c8zea4Z/F4nq0KGDxnv27HFjS5cu1Xjq1KluzP7d7dq1K6nfnQh21AAAAAAAAEQED2oAAAAAAAAiggc1AAAAAAAAEZHRGjW2HbeISIsWLTRevHixG2vSpInG8fKETzzxRI2//PJLjWO10iuIzUnbuHGjxrbtdGj16tXuOJdr1Fi2HkWybr/9do0bNWoUc57NDy3oGNF0xx13aBz+vXAepc/48eM1tu2zk2XbkG7fvt2N1alTR2PbJnbmzJlu3sEHH1zkdWSzMDfbtldevny5xn/5y18ytqbzzz8/Y78LBWvevLk7btOmTcy59v5mwoQJaVtTNqhWrZo7/tWvfhVz7tVXX62xvW9MN1uX5t133405L6xRE9Z3xE9uu+02jW3L9USFddfOPPNMjcMW37aeTTprWmSjeHVjWrZsqbFtyRyaMWOGxvZ75cqVK9282rVra2xrk4qkpqYfCmafCQwYMEDj8Bw7/PDDC/z5r776yh1/+OGHGn/xxRduzH4PsbUS27dv7+bZa8LZZ5/txubPn6+xbfGdauyoAQAAAAAAiAge1AAAAAAAAERERlOf3nvvvbjHVthW7Wdha9BWrVppbLcvtWvXLuF1/fjjjxp//vnnGofpWHYLlN12jqI799xzNbatLsuUKePmff311xrffffdbuyHH35I0+pQFHXr1nXHbdu21diebyK0MUylU0891R0fd9xxGtvtu4lu5Q23dtrtx7bVpYhIt27dNI7XOviGG27QeMiQIQmtI5fce++97thu/7Zb7MPUs1Szn33h3xVbwTMvXkpOKEwTQGyPPvqoO7700ks1tveXIiKvvvpqRtYU6ty5s8bVq1d3Yy+88ILGL730UqaWVKLYtFwRkSuvvLLAeZ9++qk73rBhg8bdu3eP+foVK1bU2KZViYi8/PLLGq9fv/7Ai81h4b3/v//9b41tqpOIT/2Nlw5ohelOVljaAunx7LPPumObthav1bZ9dvDZZ59p/Mc//tHNs9/tQyeddJLG9j70ueeec/PsMwZ7DRARefrppzV+7bXXNE51Kiw7agAAAAAAACKCBzUAAAAAAAARkdHUp1TYunWrO540aVKB8+KlVcVjtxSHaVZ2i9XIkSOTen0UzKbDhFseLfvvPmXKlLSuCakRpkpYmeyWkQtsmtl//vMfNxZvK6llO3HZ7Zz33Xefmxcv1dC+xm9+8xuNq1at6uY98sgjGh966KFu7KmnntJ49+7dB1p21rjwwgs1DrsMLFu2TONMdkiz6WthqtPkyZM1/uabbzK1pJx2yimnxBwLu8nESz2El5+f747t3/ratWvdWDq79pQtW9Yd2y39N954o8bheq+66qq0rSlb2FQGEZHDDjtMY9slJrxvsZ9Pl1xyicZhukWDBg00rlGjhht78803NT7rrLM03rJlS0Jrz3YVKlTQOCxtYMsjbNq0yY399a9/1ZgSCNES3tfZbkvXXHONG8vLy9PYfjcI0+IHDRqkcbLlEqpUqaKx7T46cOBAN8+WYQnTJjOFHTUAAAAAAAARwYMaAAAAAACAiOBBDQAAAAAAQESUuBo16VCtWjWN//73v2t80EH+OZZtG01OadG88cYb7viMM84ocN6wYcPccdiuFtHXvHnzmGO2RgmKrlSpXy7pidakCWs99e3bV+MwFzxRtkbNww8/rPHgwYPdvHLlymkc/i2MGTNG4+XLlye1jpKoT58+Gtt/HxH/+ZRutt5R//79Nd67d6+b9+CDD2qcS7WEMs22E7VxKMzZnzdvXtrWlEvOOeccd2zbntvaTGE9hUTZmihdunRxYyeeeGKBPzNq1KikflcuO+SQQ9yxrfPzt7/9LebP2Va/zz//vMb2ei0iUr9+/ZivYeunpLPGUUnVq1cvje+66y43Zltm2xb1IiLbtm1L78KQtPBadvvtt2tsa9KIiHz11Vca23qxM2fOTOp329oztWrVcmP2u+X48eM1DmvTWuF6hw8frnE66/OxowYAAAAAACAieFADAAAAAAAQEaQ+iciAAQM0tu1jw1bgS5cuzdiastFRRx2lcbh1225HtekWdlu9iMj27dvTtDqkkt2qfeWVV7qxuXPnavzOO+9kbE34hW3tHLZ0TTbdKRabwmRTaERE2rVrl9LfVRJVrFjRHcdKcxBJPq0iGbatuk2jW7x4sZs3adKkjK0plyV6rmTybyTbPP744+64a9euGtesWdON2Rbpdkt8z549k/rd9jXCttvWihUrNA5bQ+PAbGvtkE1vC9PzY2nbtm3Cv3vGjBkacy+7v3gpnfa+cc2aNZlYDlLAph+J7J86be3Zs0fjDh06aHzhhRe6eY0bNy7w53fs2OGOmzRpUmAs4u9zq1evHnNN1oYNG9xxptK+2VEDAAAAAAAQETyoAQAAAAAAiIicTH06+eST3XFYXfxntgK5iMiCBQvStqZc8Nprr2lcpUqVmPNeeukljXOp20s26d69u8aVK1d2YxMnTtTYdlJAaoVd6yy7rTTd7Jb+cE3x1jhw4ECNf/3rX6d8XVERdiE5+uijNR4xYkSml6MaNGhQ4H/nc7B4xEuxSEXXIYjMnj3bHbdo0ULjVq1aubEzzzxTY9vJZOPGjW7eiy++mNDvth1E5s+fH3Pe9OnTNeb+qPDCa6pNVbPphWF6he1e2bt3b43DLjH2XAzHrr32Wo3t+71o0aKE1p7twhQXy55vf/7zn93Ym2++qTFd7qLl/fffd8c2Vdp+TxARqV27tsZPPPGExvFSQW0qVZhmFU+sdKd9+/a549dff13j3/3ud25s3bp1Cf++omBHDQAAAAAAQETwoAYAAAAAACAieFADAAAAAAAQETlZo+bss892x6VLl9b4vffe0/ijjz7K2Jqylc3/bd26dcx5kydP1jjMP0XJ07JlS43D/NJRo0Zlejk54/rrr9c4zLUtLuedd57GJ5xwghuzawzXa2vUZLPvvvvOHdsce1sjQ8TXe9qyZUtK11GtWjV3HKtewNSpU1P6exFbp06dNO7Xr1/Medu2bdOY1rWps3XrVo3DNvT2+M477yzy76pfv77Gtq6XiL8m3HbbbUX+Xbns3Xffdcf23LF1aMK6MbHqZISvN2DAAI3Hjh3rxo499liNbb0L+7mdy6pWrapxeD9ga7n96U9/cmP33nuvxs8884zGth26iK+BsmzZMo0XLlwYc01NmzZ1x/Z7IdfaAwtbZtv6TkcccYQbs/VibS3ZzZs3u3mrV6/W2P5d2O8dIiLt27cv9HqHDh3qjv/4xz9qbOtPZRI7agAAAAAAACKCBzUAAAAAAAARkTOpT2XLltXYtnkTEdm1a5fGNu1m9+7d6V9YlgnbbtttYzbFLGS39m7fvj31C0Pa1ahRQ+POnTtrvHTpUjfPtrtDatk0o0yyW5ZFRI4//niN7TUgnrCtba5cf8Otwbbl7q9+9Ss3Nm7cOI0HDx5c6N/VrFkzd2zTLerWrevGYm31j0pKXS6wn6fxWtm/8847mVgO0simc4Tnnk2tCq+TKJwwZfSiiy7S2KZlV6xYMeZrPPnkkxqHaW8//vijxqNHj3ZjNrWjR48eGjdo0MDNy9W263/96181/sMf/pDwz9lr44033lhgnCr2/LMlG/r27Zvy35XtwlQie34kY9iwYe44XuqTTTm3f2svvPCCm2fbfxcXdtQAAAAAAABEBA9qAAAAAAAAIoIHNQAAAAAAABGRMzVqbr/9do3DFrETJ07UePr06RlbUza69dZb3XG7du0KnPfGG2+4Y1pyl3xXXHGFxrbV74QJE4phNcike+65xx3bFqXxrFy5UuPLL7/cjdkWjLnEXgvDNr3nnHOOxiNGjCj0a2/atMkd21oYRx55ZEKvEeZwI31itUgPc/ufffbZTCwHKdSnTx93fNlll2ls6yeI7N+eFqlj22vb861fv35unj3nbD0hW5Mm9MADD7jjJk2aaNyzZ88CX09k/8/CXGFrlIwcOdKN/fvf/9a4VCn/1bVWrVoax6vllQq2Hp/9e7EtwkVEHnzwwbSuAz+54447NC5MnaDrr79e42TupTKJHTUAAAAAAAARwYMaAAAAAACAiMja1Ce7RVxE5P/+7/80/vbbb93Y/fffn5E15YJEW+r99re/dce05C756tSpU+B/37p1a4ZXgkwYP368xscdd1xSr7Fo0SKNp06dWuQ1ZYMlS5ZobFvHioi0atVK44YNGxb6tW372dCLL77ojvv371/gvLCdOFLnmGOOccdh+sXP1qxZ445nzZqVtjUhPc4666yYY2PHjnXHc+bMSfdyID4NysbJCq+VNp3Hpj517drVzatcubLGYTvxbGZbIYfXtEaNGsX8udNOO03j0qVLazxw4EA3L1YphmTZ1OQ2bdqk9LUR2zXXXKOxTTkLU+KshQsXuuPRo0enfmFpwo4aAAAAAACAiOBBDQAAAAAAQERkVepTlSpVNH7iiSfc2MEHH6yx3bIvIjJjxoz0Lgz7sVs7RUR2795d6NfYtm1bzNew2x8rVqwY8zWOOOIId5xo6pbdonnnnXe6sR9++CGh18g25557boH//a233srwSnKX3Yobr/tBvG33Q4cO1bhmzZox59nX37dvX6JLdM4777ykfi5XzZs3r8A4FVasWJHQvGbNmrnjBQsWpHQdueykk05yx7HO4bBrIkqe8Br8/fffa/zoo49mejnIgFdeeUVjm/p08cUXu3m2NAClGQ7svffeK/C/21RhEZ/6tGfPHo2ff/55N+8f//iHxr///e/dWKx0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agAAAAAAACIio6lPiaY6hXbu3Klx2B3KWrZsmcbz5s1zY1u3bk3od3Xt2lXjcJuT3eq/atWqhF4PBbNbR0X8Fl67dTvs7GS39oZbj+2W1ooVK2ocpjqluiNKSZRMqlOywlQJ20Hmv//9rxvbsGFDRtaUC2rWrOmObcV6mzIapkbY98ReN22KqIhPvQn/nuz2UbuORo0auXn2OpCKdLxscPfdd2scdvCxn2tTpkwp9Gvbrf0i8dM37N+LTV+rU6eOm/fYY49pzLU1fey/u+1UI+KvqWFq97Rp09K7sCwSphI9++yzGtv7SxHfjdSmiKYitdp2NRERufzyyzVu165dzDWNGDGiyL8729l/PxGRqlWramw7Ho4cOdLNs9feU089VWObFiri053C+9yWLVtqbFMlli5dmsjSc4rtUinir3mffPKJG7PXPHvPEqZr288n29EtWbaTUNj5Ej+xJUlERG688UaNbScvEX9fajvA2lQnEZGJEydqnGiamv3+LuK71to0u3C9ZcuW1XjTpk1uLN7ziFRiRw0AAAAAAEBE8KAGAAAAAAAgInhQAwAAAAAAEBEZrVGTSYnWpBHxLRm7d++ucZkyZdw82lymTpgnbOshzJgxQ+Pw33zOnDkaz5w5042VK1dOY5t/iOJlc8BFRFavXq0x9RPSx9ZQEIld++nNN99081544QWNk827tjn369at0zisrdG0aVON+/fv78aGDh2a1O8uaWz9FxFflyZsL2prdCVaJ83WNgnbqMdjPwtt7bbNmze7eWG9AKSHbUEbfr7ZWiUffPCBG6OeXuLCGk4//PCDxvXr13djRx99tMb2nAjrrNn6Nd98843GYQ0uex960kknubEbbrhBY1uTIaxTlYr6ONnO1nMKj20L7nfffTfma9g6br169XJjRxxxhMa25oaIr9cWrgNe2ILb1hgJvxfEao0c1qGx90DJst8Lbf0SatQUrF69eu7Yfh8I68Da+xN7Dxl+10u0Lo09xypXruzGGjRooHGXLl00PuWUU9w8W+doxYoVbixT9z58mwUAAAAAAIgIHtQAAAAAAABERNamPhXGFVdcobHdih+287LbIlF4dvt82NLQbkuzbX/DtoXhFjjLblNG6titfzt37kzoZ+x5FG59tFvDbSpHPLb1uojI3r17E/q5XGPby4atsO17Z7duDxs2zM1LxRZe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\n",
      "text/plain": [
       "<Figure size 1440x288 with 20 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "number = 10  # how many digits we will display\n",
    "plt.figure(figsize=(20, 4))\n",
    "for index in range(number):\n",
    "    # display original\n",
    "    ax = plt.subplot(2, number, index + 1)\n",
    "    plt.imshow(x_test[index].reshape(28, 28), cmap='gray')\n",
    "    ax.get_xaxis().set_visible(False)\n",
    "    ax.get_yaxis().set_visible(False)\n",
    "\n",
    "    # display reconstruction\n",
    "    ax = plt.subplot(2, number, index + 1 + number)\n",
    "    plt.imshow(model(x_test)[index].numpy().reshape(28, 28), cmap='gray')\n",
    "    ax.get_xaxis().set_visible(False)\n",
    "    ax.get_yaxis().set_visible(False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tf2p0alpha]",
   "language": "python",
   "name": "conda-env-tf2p0alpha-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
